using System;
using CodePlex.DnD4eCampaignManager.DnD4e;
using CodePlex.DnD4eCampaignManager.DnD4e.Interfaces;
using NUnit.Framework;

namespace CodePlex.DnD4eCampaignManager.CampaignManagerTests.DnD4eTests
{
    [TestFixture]
    public class HitPointsTests
    {
        private const int MAX_HIT_POINTS = 30;
        private const int STARTING_TEMPORARY_HIT_POINTS = 10;

        [Test]
        public void HitPointsCurrentCannotExceedHitPointsMaximum()
        {
            HitPoints hitPoints = new HitPoints { HitPointsMaximum = MAX_HIT_POINTS, HitPointsCurrent = MAX_HIT_POINTS + 5 };
            Assert.AreEqual(MAX_HIT_POINTS, hitPoints.HitPointsCurrent);
        }

        [Test]
        public void DamageAppliesToTemporaryHitPointsFirst()
        {
            HitPoints hitPoints = GetNewHitPoints();
            Assert.AreEqual(STARTING_TEMPORARY_HIT_POINTS, hitPoints.HitPointsTemporary);
            int hitPointsLost = STARTING_TEMPORARY_HIT_POINTS / 2;
            hitPoints.Damage(hitPointsLost);
            Assert.AreEqual(MAX_HIT_POINTS, hitPoints.HitPointsCurrent);
            Assert.AreEqual(STARTING_TEMPORARY_HIT_POINTS - hitPointsLost, hitPoints.HitPointsTemporary);
            hitPoints.Damage(STARTING_TEMPORARY_HIT_POINTS - hitPointsLost);
            Assert.AreEqual(MAX_HIT_POINTS, hitPoints.HitPointsCurrent);
            Assert.AreEqual(0, hitPoints.HitPointsTemporary);
            hitPointsLost = MAX_HIT_POINTS / 2;
            hitPoints.Damage(hitPointsLost);
            Assert.AreEqual(MAX_HIT_POINTS - hitPointsLost, hitPoints.HitPointsCurrent);
            Assert.AreEqual(0, hitPoints.HitPointsTemporary);
        }

        [Test]
        public void DamageReducesTotalHitPoints()
        {
            const int damageAmount = 6;
            const int expectedFinalHitPoints = MAX_HIT_POINTS + STARTING_TEMPORARY_HIT_POINTS - damageAmount;
            HitPoints hitPoints = GetNewHitPoints();
            hitPoints.Damage(damageAmount);
            int actualFinalHitPoints = hitPoints.HitPointsCurrent + hitPoints.HitPointsTemporary;
            Assert.AreEqual(expectedFinalHitPoints, actualFinalHitPoints);
        }

        [Test]
        public void HasHitPointsCurrent()
        {
            HitPoints hitPoints = GetNewHitPoints();
            Assert.AreEqual(MAX_HIT_POINTS, hitPoints.HitPointsCurrent);
        }

        [Test]
        public void HasHitPointsMaximum()
        {
            HitPoints hitPoints = GetNewHitPoints();
            Assert.AreEqual(MAX_HIT_POINTS, hitPoints.HitPointsMaximum);
        }

        [Test]
        public void HasHitPointsTemporary()
        {
            HitPoints hitPoints = GetNewHitPoints();
            Assert.AreEqual(STARTING_TEMPORARY_HIT_POINTS, hitPoints.HitPointsTemporary);
        }

        [Test]
        public void ImplementsIEquatable()
        {
            Assert.IsInstanceOfType(typeof ( IEquatable<HitPoints> ), new HitPoints());
        }


        [Test]
        public void ImplementsIHitPoints()
        {
            Assert.IsInstanceOfType(typeof ( IHitPoints ), new HitPoints());
        }


        private static HitPoints GetNewHitPoints()
        {
            return new HitPoints
                       {
                           HitPointsMaximum = MAX_HIT_POINTS,
                           HitPointsCurrent = MAX_HIT_POINTS,
                           HitPointsTemporary = STARTING_TEMPORARY_HIT_POINTS
                       };
        }
    }
}